#include "tests.h"
#include "ISet.h"
#include <cstdlib>
#include <stdexcept>
#include <vector>


std::vector<int> generateRandomSequence()
{
    const size_t MAX_SIZE = 1024;
    const size_t size = rand() % MAX_SIZE;
    std::vector<int> result;
    result.reserve(size);
    for (size_t i = 0; i < size; ++i) {
        result.push_back(rand());
    }
    return result;
}


void testISetForeach(const ISet& set, std::vector<int> elements)
{
    std::vector<int> set_elements;
    set.foreach([&set_elements](int value) {
        set_elements.push_back(value);
    });
    std::sort(set_elements.begin(), set_elements.end());
    std::sort(elements.begin(), elements.end());
    elements.erase(
        std::unique(elements.begin(), elements.end()), elements.end());
    if (set_elements != elements) {
        throw std::logic_error("ISet::foreach: FAIL");
    }
}


void testUnorderedSetForeach(const std::vector<int>& elements)
{
    try {
        testISetForeach(UnorderedSet(elements), elements);
    } catch (const std::exception& ex) {
        throw std::logic_error("UnorderedSetForeach: " + std::string(ex.what()));
    }
}


void testBitSetForeach(const std::vector<int>& elements)
{
    try {
        testISetForeach(BitSet(elements), elements);
    } catch (const std::exception& ex) {
        throw std::logic_error("BitSetForeach: " + std::string(ex.what()));
    }
}

void testISet()
{
    testUnorderedSetForeach({});
    testBitSetForeach({});
    testUnorderedSetForeach({1});
    testBitSetForeach({1});
    testUnorderedSetForeach({-100500, 2, 100500});
    testBitSetForeach({-100500, 2, 100500});
    for (int case_no = 0; case_no < 1024; ++case_no) {
        const auto sequence = generateRandomSequence();
        testUnorderedSetForeach(sequence);
        testBitSetForeach(sequence);
    }
}
